/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.test.core.enums

import com.fasterxml.jackson.annotation.JsonCreator
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertNotNull
import org.junit.jupiter.api.assertNull
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import tony.core.enums.IntEnumValue
import tony.core.enums.StringEnumValue
import tony.core.enums.getEnum

/**
 * 枚举工具类与扩展测试
 *
 * @author tangli
 * @date 2025/06/27 17:00
 */
@DisplayName("枚举工具类与扩展测试")
class EnumsTest {

    // 测试用枚举
    enum class TestIntEnum(override val value: Int) : IntEnumValue {
        ONE(1), TWO(2), THREE(3), DEFAULT(-1);
        companion object  {
            @JvmStatic
            @JsonCreator
            fun create(value: Int): TestIntEnum? {
                return TestIntEnum::class.java.getEnum(value)
            }
        }
    }

    enum class TestStringEnum(override val value: String) : StringEnumValue {
        HELLO("hello"), WORLD("world"), TONY("tony"), DEFAULT("");

        companion object  {
            @JvmStatic
            @JsonCreator
            fun create(value: String): TestStringEnum? {
                return TestStringEnum::class.java.getEnum(value.lowercase())
            }
        }
    }

    @Nested
    @DisplayName("IntEnumCreator/StringEnumCreator/EnumCreator")
    inner class EnumCreatorTest {
        @Test
        @DisplayName("IntEnumCreator创建器")
        fun testIntEnumCreator() {
            assertEquals(TestIntEnum.ONE, TestIntEnum.create(1))
            assertEquals(TestIntEnum.TWO, TestIntEnum.create(2))
            assertEquals(TestIntEnum.THREE, TestIntEnum.create(3))
            assertNull(TestIntEnum.create(999))
            assertEquals(TestIntEnum.DEFAULT, TestIntEnum.create(-1))
        }

        @Test
        @DisplayName("StringEnumCreator创建器")
        fun testStringEnumCreator() {
            assertEquals(TestStringEnum.HELLO, TestStringEnum.create("hello"))
            assertEquals(TestStringEnum.WORLD, TestStringEnum.create("world"))
            assertEquals(TestStringEnum.TONY, TestStringEnum.create("tony"))
            assertNull(TestStringEnum.create("invalid"))
            assertEquals(TestStringEnum.DEFAULT, TestStringEnum.create(""))
            // 大小写不敏感
            assertEquals(TestStringEnum.HELLO, TestStringEnum.create("HELLO"))
        }
    }

    @Nested
    @DisplayName("序列化与边界")
    inner class SerializationAndEdge {
        @Test
        @DisplayName("枚举序列化/反序列化")
        fun testEnumSerialization() {
            val intEnum = TestIntEnum.ONE
            val intValue = intEnum.value
            assertEquals(intEnum, TestIntEnum.create(intValue))
            val stringEnum = TestStringEnum.HELLO
            val stringValue = stringEnum.value
            assertEquals(stringEnum, TestStringEnum.create(stringValue))
        }

        @Test
        @DisplayName("边界情况")
        fun testEdgeCases() {
            assertEquals(TestStringEnum.DEFAULT, TestStringEnum.create(""))
            assertNull(TestIntEnum.create(0)) // 假设0不是有效值
        }
    }

    @Nested
    @DisplayName("性能与并发")
    inner class PerformanceAndConcurrency {
        @Test
        @DisplayName("性能测试")
        fun testPerformance() {
            val iterations = 10000
            val t1 = System.currentTimeMillis()
            repeat(iterations) {
                TestIntEnum.create(1)
                TestStringEnum.create("hello")
            }
            val t2 = System.currentTimeMillis()
            assertTrue(t2 > t1)
        }

        @Test
        @DisplayName("并发安全测试")
        fun testConcurrency() {
            val threadCount = 10
            val iterationsPerThread = 1000
            val threads = mutableListOf<Thread>()
            repeat(threadCount) {
                threads += Thread {
                    repeat(iterationsPerThread) {
                        assertEquals(TestIntEnum.ONE, TestIntEnum.create(1))
                        assertEquals(TestStringEnum.HELLO, TestStringEnum.create("hello"))
                    }
                }.apply { start() }
            }
            threads.forEach { it.join() }
        }
    }

    @Nested
    @DisplayName("参数化典型用例")
    inner class ParameterizedCases {
        @ParameterizedTest
        @ValueSource(ints = [1, 2, 3, -1, 0, 999])
        @DisplayName("参数化IntEnum创建")
        fun testParamIntEnumCreate(value: Int) {
            val result = TestIntEnum.create(value)
            when (value) {
                in 1..3 -> {
                    assertNotNull(result)
                }
                -1 -> {
                    assertEquals(TestIntEnum.DEFAULT, result)
                }
                else -> {
                    assertNull(result)
                }
            }
        }

        @ParameterizedTest
        @ValueSource(strings = ["hello", "world", "tony", "", "HELLO", "invalid"])
        @DisplayName("参数化StringEnum创建")
        fun testParamStringEnumCreate(value: String) {
            val result = TestStringEnum.create(value)
            if (value.lowercase() in listOf("hello", "world", "tony")) {
                assertNotNull(result)
            } else if (value == "") {
                assertEquals(TestStringEnum.DEFAULT, result)
            } else {
                assertNull(result)
            }
        }
    }
}
